import { HEAD_OF_CALLBACK, VERSION } from './config';
import {
    isWPTIos, isWPTAndroid, getUuid, logError, isWPTApp
} from './util';
import CallbackAggregate from './class/CallbackAggregate';
import ForNativeJsAggregete from './class/ForNativeJsAggregete';

/**
 *处理回调函数
 *
 * @param {*} callBack
 * @param {*} failCallBack
 */
function handleCallBack(callBack, failCallBack = null) {
    let CB_NAME;
    if (callBack) {
        CB_NAME = HEAD_OF_CALLBACK + getUuid();
        CallbackAggregate.add(CB_NAME, callBack, failCallBack);
    }

    return CB_NAME || '';
}

/**
 *处理Js传递给原生的参数
 *
 * @param {*} data
 * @param {number} [type=1] 1:js调用原生方法，2：js回调原生
 * @returns
 */
function handleJsParams(data, type = 1) {
    const { name, params, eventId } = data;
    if (typeof name !== 'string' && type === 1) {
        logError('错误的方法名类型');
        return '';
    }

    if (typeof eventId !== 'string') {
        logError('eventId 必须是字符串');
        return '';
    }

    return type === 1
        ? JSON.stringify({
            name,
            eventId,
            global: false,
            params,
            version: VERSION,
        })
        : JSON.stringify({
            eventId,
            object: {
                code: 0,
                meg: '',
                data: params,
            },
            version: VERSION,
        });
}

/**
 *调用原生挂载的方法
 *
 * @param {*} data
 * @param {*} name
 */
function callNative(name, data) {
    if (!isWPTApp) {
        logError('请检查当前环境');
        return;
    }

    if (typeof name !== 'string') {
        logError('调用的方法名必须为string');
        return;
    }

    if (isWPTIos) {
        if (!window.webkit || !window.webkit.messageHandlers || !window.webkit.messageHandlers[name]) {
            logError(`请检查ios方法是否挂载成功,${name}`);
            return;
        }
        window.webkit.messageHandlers[name].postMessage(data);
        return;
    }

    if (isWPTAndroid) {
        if (!window.wxx || !window.wxx[name]) {
            logError(`请检查android方法是否挂载成功,${name}`);
            return;
        }
        window.wxx[name](data);
    }
}

/**
 * 统一处理业务调用
 *
 * @param {*} name
 * @param {*} params
 * @param {*} callBack
 * @param {*} failCallBack
 */
function wptBridgeJsCallNative(name, params, callBack, failCallBack) {
    if (typeof params === 'function' && typeof failCallBack === 'undefined') {
        [failCallBack, callBack, params] = [callBack, params, {}];
    }

    const eventId = handleCallBack(callBack, failCallBack);
    const rParams = handleJsParams({
        eventId,
        name,
        params,
    });

    if (!rParams) {
        CallbackAggregate.remove(eventId);
        return;
    }

    callNative('wptBridgeJsCallNative', rParams);
}

/**
 *从回调函数池中调用回调函数
 *
 * @param {*} eventId
 * @param {*} complete
 * @param {*} object
 * @returns
 */
function wptBridgeCbHandle(eventId, complete, object) {
    if (typeof eventId !== 'string') {
        logError('eventId值有误');
        return;
    }

    CallbackAggregate.call({
        CB_NAME: eventId,
        type: object.code,
        object,
    });

    if (complete) {
        CallbackAggregate.remove(eventId);
    }
}

/**
 *原生回调js方法
 *
 * @param {*} data
 */
function wptBridgeNativeCallBack(data) {
    if (!(typeof data !== 'object' || typeof data !== 'string')) {
        logError('回传数据有误');
        return;
    }

    let tmp;
    if (typeof data === 'string') {
        tmp = JSON.parse(data);
    } else {
        tmp = data;
    }

    const { eventId, complete, object } = tmp;

    wptBridgeCbHandle(eventId, complete, object);
}

/**
 *原生直接调用js方法
 *
 * @param {*} data
 */
function wptBridgeNativeCallJs(data) {
    if (typeof data !== 'object' || !data.name) {
        logError('传递参数错误或未传递调用的方法名');
        return;
    }

    ForNativeJsAggregete.call(data);
}

/**
 *js回调原生
 *
 * @param {*} data
 * @returns
 */
function wptBridgeJsCallBack(data) {
    const { eventId, params } = data;
    const rParams = handleJsParams(
        {
            eventId,
            params,
        },
        2
    );

    if (!rParams) return;

    callNative('wptBridgeJsCallBack', rParams);
}

/**
 * 注册给原生调用的全局方法
 *
 * @param {string} NAME
 * @param {Function} callback
 * @returns {Function} unRegistryFn
 */
function wptBridgeRegisterForNativeJs(NAME, callback = () => undefined) {
    if (!isWPTApp) {
        return () => undefined;
    }

    ForNativeJsAggregete.add(NAME, callback);

    return () => {
        ForNativeJsAggregete.remove(NAME, callback);
    };
}

export {
    wptBridgeJsCallNative,
    wptBridgeJsCallBack,
    handleCallBack,
    handleJsParams,
    wptBridgeNativeCallBack,
    wptBridgeNativeCallJs,
    wptBridgeCbHandle,
    wptBridgeRegisterForNativeJs
};
